package org.jsola.contract.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.jsola.common.DateKit8;
import org.jsola.common.StrKit;
import org.jsola.contract.dao.IContractDAO;
import org.jsola.contract.dao.IContractStatisticsDAO;
import org.jsola.contract.entity.ContractDO;
import org.jsola.contract.query.ContractQuery;
import org.jsola.contract.service.IContractOverviewService;
import org.jsola.contract.service.IContractService;
import org.jsola.contract.service.IPartySignService;
import org.jsola.contract.vo.*;
import org.jsola.core.Page;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import static org.jsola.contract.constant.ContractConstants.*;

/**
 * 年月周 合同签署统计
 *
 * @author huangrun
 */
@Service("contractContractOverviewServiceImpl")
public class ContractOverviewServiceImpl implements IContractOverviewService {

    private static final Logger log = LoggerFactory.getLogger(ContractOverviewServiceImpl.class);

    @Autowired
    private IContractDAO contractDAO;

    @Autowired
    private IContractService contractService;

    @Autowired
    private IPartySignService partySignService;

    @Autowired
    private IContractStatisticsDAO contractStatisticsDAO;


    @Override
    public List<ContractOfSignForListVO> selectMonthForListCount(String siteId) {
        // 存放查询的结果集
        List<ContractStatisticsForListVO> listOfSelectResult = new ArrayList<>();
        // 临时存放时间日期 遍历使用
        List<ContractStatisticsForListVO> listSetDate = new ArrayList<>();

        // 待员工签署
        List<ContractStatisticsVO> listEmpCount = contractStatisticsDAO.selectMonthForListCount(CONTRACT_STATUS_PERSON, siteId);
        doTraversalQueryForList(listOfSelectResult, listSetDate, CONTRACT_STATUS_PERSON, listEmpCount);
        // 待企业签署
        List<ContractStatisticsVO> listComCount = contractStatisticsDAO.selectMonthForListCount(CONTRACT_STATUS_ENTERPRISE, siteId);
        doTraversalQueryForList(listOfSelectResult, listSetDate, CONTRACT_STATUS_ENTERPRISE, listComCount);
        // 签署完成
        List<ContractStatisticsVO> listSigCompCount = contractStatisticsDAO.selectMonthForListCount(CONTRACT_STATUS_FINISH, siteId);
        doTraversalQueryForList(listOfSelectResult, listSetDate, CONTRACT_STATUS_FINISH, listSigCompCount);
        return dealingWithListResult(listSetDate, listOfSelectResult);
    }

    @Override
    public List<ContractOfSignForListVO> selectWeekForListCount(String siteId) {
        // 存放查询的结果集
        List<ContractStatisticsForListVO> listOfSelectResult = new ArrayList<>();
        // 临时存放时间日期 遍历使用
        List<ContractStatisticsForListVO> listSetDate = new ArrayList<>();

        // 待员工签署
        List<ContractStatisticsVO> listEmpCount = contractStatisticsDAO.selectWeekForListCount(CONTRACT_STATUS_PERSON, siteId);
        doTraversalQueryForList(listOfSelectResult, listSetDate, CONTRACT_STATUS_PERSON, listEmpCount);
        // 待企业签署
        List<ContractStatisticsVO> listComCount = contractStatisticsDAO.selectWeekForListCount(CONTRACT_STATUS_ENTERPRISE, siteId);
        doTraversalQueryForList(listOfSelectResult, listSetDate, CONTRACT_STATUS_ENTERPRISE, listComCount);
        // 签署完成
        List<ContractStatisticsVO> listSigCompCount = contractStatisticsDAO.selectWeekForListCount(CONTRACT_STATUS_FINISH, siteId);
        doTraversalQueryForList(listOfSelectResult, listSetDate, CONTRACT_STATUS_FINISH, listSigCompCount);
        return dealingWithListResult(listSetDate, listOfSelectResult);
    }

    @Override
    public List<ContractOfSignForListVO> selectContractCountDay(Date startDate, Date endDate,
                                                                List<String> subjectIds, String siteId) {
        return getContractOfSign(startDate, endDate, subjectIds, siteId, "Day");
    }

    @Override
    public List<ContractOfSignForListVO> selectContractCountMonth(Date startDate, Date endDate
            , List<String> subjectIds, String siteId) {
        return getContractOfSign(startDate, endDate, subjectIds, siteId, "Month");
    }

    private List<ContractOfSignForListVO> getContractOfSign(Date startDate, Date endDate
            , List<String> subjectIds, String siteId, String type) {
        List<ContractOfSignForListVO> contractOfSignForListVOList = new ArrayList<>();
        startDate = DateKit8.getStartTime(startDate);
        endDate = DateKit8.getEndTime(endDate);
        // 查询发起日期在时间范围内的合同
        List<ContractDO> contractDOList = contractService.selectBySiteIdAndDate(siteId, startDate, endDate, subjectIds);
        Map<String, List<String>> gmtCreateListMap;
        // 查询合同按发起签署时间(创建时间)分组 以天为维度
        if (CollectionUtils.isEmpty(contractDOList)) {
            gmtCreateListMap = new HashMap<>();
        } else {
            if ("Day".equals(type)) {
                // 以天为单位
                gmtCreateListMap = contractDOList.parallelStream().map(contractDO
                        -> DateKit8.format(contractDO.getGmtCreate(), DateKit8.DATE)).collect(Collectors.groupingBy(v -> v));
            } else {
                // 以月为单位
                gmtCreateListMap = contractDOList.parallelStream().map(contractDO
                        -> DateKit8.format(contractDO.getGmtCreate(), "yyyy-MM")).collect(Collectors.groupingBy(v -> v));
            }
        }
        while (startDate.getTime() < endDate.getTime()) {
            // 构造统计值
            ContractOfSignForListVO contractOfSignForListVO = new ContractOfSignForListVO();
            List<Map<String, String>> countList = new ArrayList<>();
            contractOfSignForListVO.setSortDate(startDate);
            // 日期转换
            String dateString;
            if ("Day".equals(type)) {
                // 以天为单位
                dateString = DateKit8.format(startDate, DateKit8.DATE);
            } else {
                // 以月为单位
                dateString = DateKit8.format(startDate, "yyyy-MM");
            }
            contractOfSignForListVO.setDate(dateString);
            List<String> stringList = gmtCreateListMap.get(dateString);
            Map<String, String> countMap = new HashMap<>();
            if (CollectionUtils.isEmpty(stringList)) {
                countMap.put("toSignedByComCount", "0");
            } else {
                countMap.put("toSignedByComCount", stringList.size() + "");
            }
            countList.add(countMap);
            contractOfSignForListVO.setList(countList);
            // 添加到返回List
            contractOfSignForListVOList.add(contractOfSignForListVO);
            // 开始时间加一
            if ("Day".equals(type)) {
                // 以天为单位
                startDate = DateKit8.addDays(startDate, 1);
            } else {
                // 以月为单位
                startDate = DateKit8.addMonths(startDate, 1);
            }
        }
        return contractOfSignForListVOList;
    }

    @Override
    public List<ContractOfSignForListVO> selectYearForListCount(String siteId) {
        // 存放查询的结果集
        List<ContractStatisticsForListVO> listOfSelectResult = new ArrayList<>();
        // 临时存放时间日期 遍历使用
        List<ContractStatisticsForListVO> listSetDate = new ArrayList<>();
        // 待员工签署
        List<ContractStatisticsVO> listEmpCount = contractStatisticsDAO.selectYearForListCount(CONTRACT_STATUS_PERSON, siteId);
        doTraversalQueryForList(listOfSelectResult, listSetDate, CONTRACT_STATUS_PERSON, listEmpCount);
        // 待企业签署
        List<ContractStatisticsVO> listComCount = contractStatisticsDAO.selectYearForListCount(CONTRACT_STATUS_ENTERPRISE, siteId);
        doTraversalQueryForList(listOfSelectResult, listSetDate, CONTRACT_STATUS_ENTERPRISE, listComCount);
        // 签署完成
        List<ContractStatisticsVO> listSigCompCount = contractStatisticsDAO.selectYearForListCount(CONTRACT_STATUS_FINISH, siteId);
        doTraversalQueryForList(listOfSelectResult, listSetDate, CONTRACT_STATUS_FINISH, listSigCompCount);
        return dealingWithListResult(listSetDate, listOfSelectResult);
    }

    @Override
    public List<ContractOfSignForListVO> selectTwoTimePeriodsForCount(String startTime, String endTime, String siteId) {
        // 存放查询的结果集
        List<ContractStatisticsForListVO> listOfSelectResult = new ArrayList<>();
        // 临时存放时间日期 遍历使用
        List<ContractStatisticsForListVO> listSetDate = new ArrayList<>();

        try {
            // 获取两段时间间隔的所有月份
            List<String> lastDateForMonth = getMonthBetween(startTime, endTime);

            // 待员工签署
            List<ContractStatisticsVO> listEmpCount = contractStatisticsDAO.selectTwoTimePeriodsForCount(lastDateForMonth, CONTRACT_STATUS_PERSON, startTime, endTime, siteId);
            doTraversalQueryForList(listOfSelectResult, listSetDate, CONTRACT_STATUS_PERSON, listEmpCount);
            // 待企业签署
            List<ContractStatisticsVO> listComCount = contractStatisticsDAO.selectTwoTimePeriodsForCount(lastDateForMonth, CONTRACT_STATUS_ENTERPRISE, startTime, endTime, siteId);
            doTraversalQueryForList(listOfSelectResult, listSetDate, CONTRACT_STATUS_ENTERPRISE, listComCount);
            // 签署完成
            List<ContractStatisticsVO> listSigCompCount = contractStatisticsDAO.selectTwoTimePeriodsForCount(lastDateForMonth, CONTRACT_STATUS_FINISH, startTime, endTime, siteId);
            doTraversalQueryForList(listOfSelectResult, listSetDate, CONTRACT_STATUS_FINISH, listSigCompCount);
            return dealingWithListResultForTowTimePeriods(lastDateForMonth, listOfSelectResult);
        } catch (Exception e) {
            log.error(e.getMessage());
            return null;
        }

    }

    @Override
    public Page<ContractListVO> selectPage(ContractQuery contractQuery, String siteId) {
        PageInfo<ContractListVO> pageInfo = PageHelper.startPage(contractQuery.getPageNo(), contractQuery.getPageSize())
                .doSelectPageInfo(() -> contractStatisticsDAO.selectContractRecordDetails(contractQuery, siteId));
        return new Page<>(pageInfo.getList(), pageInfo.getPageNum(), pageInfo.getPageSize(), (int) pageInfo.getTotal());
    }

    @Override
    public Page<ContractListVO> selectPageBySubjectIds(ContractQuery contractQuery, String siteId) {
        // 构造查询参数(业务ids、状态、电话等)
        Example example = new Example(ContractDO.class);
        example.and().andEqualTo("siteId", siteId);
        if (!CollectionUtils.isEmpty(contractQuery.getSubjectIds())) {
            example.and().andIn("subjectId", contractQuery.getSubjectIds());
        }
        if (contractQuery.getStatus() != null) {
            example.and().andEqualTo("status", contractQuery.getStatus());
        }
        String contractNameOrNoOrSignNo = contractQuery.getContractNameOrNoOrSignNo();
        if (StrKit.isNotEmpty(contractNameOrNoOrSignNo)) {
            example.and()
                    .orLike("partyBName", "%" + contractNameOrNoOrSignNo + "%")
                    .orLike("partyBPhone", "%" + contractNameOrNoOrSignNo + "%");
        }
        example.orderBy("gmtCreate").desc();
        // 分页查询
        Page<ContractDO> page = contractDAO
                .selectPageByExample(example, contractQuery.getPageNo(), contractQuery.getPageSize());
        return page.to(ContractListVO.class);
    }

    @Override
    public Page<ContractStatisticsEmpUnitsVO> selectComForRankCount(ContractQuery contractQuery, String siteId) {
        PageInfo<ContractStatisticsEmpUnitsVO> pageInfo = PageHelper.startPage(contractQuery.getPageNo(), contractQuery.getPageSize())
                .doSelectPageInfo(() -> contractStatisticsDAO.selectComForRank(siteId));

        return new Page<>(pageInfo.getList(), pageInfo.getPageNum(), pageInfo.getPageSize(), (int) pageInfo.getTotal());
    }

    @Override
    public List<ContractStatisticsEmpUnitsVO> selectComForRankCountList(String siteId) {
        return contractStatisticsDAO.selectComForRank(siteId);
    }

    /**
     * 合同签署统计查询结果集处理
     *
     * @param listSetDate        临时存放时间日期
     * @param listOfSelectResult 查询结果集合
     * @return 最终处理结果集合
     */
    private List<ContractOfSignForListVO> dealingWithListResult(List<ContractStatisticsForListVO> listSetDate, List<ContractStatisticsForListVO> listOfSelectResult) {
        //遍历查询结果集合listOfSelectResult  -->将元素遍历 取签约统计数
        return listSetDate.parallelStream().map(contractStatisticsForListVO -> {
            ContractOfSignForListVO listVO = new ContractOfSignForListVO();
            // 先存放 date 时间
            listVO.setDate(contractStatisticsForListVO.getDate());
            String date = contractStatisticsForListVO.getDate();
            if (date.length() < 8) {
                date += "-01";
            }
            listVO.setSortDate(DateKit8.parseDateTime(date));
            // 新开空间 避免重复
            List<Map<String, String>> mapList = listOfSelectResult.parallelStream().map(listResult -> {
                // 如果时间相同 添加mapList
                if (listResult.getDate().equals(contractStatisticsForListVO.getDate())) {
                    return listResult.getSum();
                }
                return null;
            }).filter(Objects::nonNull).collect(Collectors.toList());
            listVO.setList(mapList);
            return listVO;
        }).sorted(Comparator.comparing(ContractOfSignForListVO::getSortDate)).collect(Collectors.toList());
    }

    /**
     * 遍历不同签署状态的结果集合
     *
     * @param listOfSelectResult 存放查询的结果集
     * @param listSetDate        临时存放时间日期
     * @param status             状态码
     * @param list               查询结果集合
     */
    private void doTraversalQueryForList(List<ContractStatisticsForListVO> listOfSelectResult, List<ContractStatisticsForListVO> listSetDate, int status, List<ContractStatisticsVO> list) {
        // 为查询到数据添加标签
        Map<String, String> mapCount = null;
        if (status == CONTRACT_STATUS_PERSON) {
            //遍历
            for (ContractStatisticsVO count : list) {
                ContractStatisticsForListVO statisticsForListVO = new ContractStatisticsForListVO();
                mapCount = new HashMap<>(16);
                mapCount.put("toSignedByEmpCount", count.getCount());
                statisticsForListVO.setSum(mapCount);
                statisticsForListVO.setDate(count.getDate());
                listOfSelectResult.add(statisticsForListVO);

                // 临时存放时间日期 遍历使用
                listSetDate.add(statisticsForListVO);
            }
        } else if (status == CONTRACT_STATUS_ENTERPRISE) {
            for (ContractStatisticsVO count : list) {
                ContractStatisticsForListVO statisticsForListVO = new ContractStatisticsForListVO();
                mapCount = new HashMap<>(16);
                mapCount.put("toSignedByComCount", count.getCount());
                statisticsForListVO.setSum(mapCount);
                statisticsForListVO.setDate(count.getDate());
                listOfSelectResult.add(statisticsForListVO);
            }
        } else if (status == CONTRACT_STATUS_FINISH) {
            for (ContractStatisticsVO count : list) {
                ContractStatisticsForListVO statisticsForListVO = new ContractStatisticsForListVO();
                mapCount = new HashMap<>(16);
                mapCount.put("signedCompleteCount", count.getCount());
                statisticsForListVO.setSum(mapCount);
                statisticsForListVO.setDate(count.getDate());
                listOfSelectResult.add(statisticsForListVO);
            }
        }
    }

    /**
     * 合同签署统计查询结果集处理
     *
     * @param listOfSelectResult 查询结果集合
     * @param lastDateForMonth   间隔的月份
     * @return 最终处理结果集合
     */
    private List<ContractOfSignForListVO> dealingWithListResultForTowTimePeriods(List<String> lastDateForMonth, List<ContractStatisticsForListVO> listOfSelectResult) throws Exception {
        List<ContractOfSignForListVO> listLast = new ArrayList<>();
        //遍历listMap 将元素遍历 取签约统计数 * 3
        lastDateForMonth.forEach(str -> {
            ContractOfSignForListVO listVO = new ContractOfSignForListVO();
            // 先存放 date 时间
            listVO.setDate(str);
            // 新开空间 避免重复
            List<Map<String, String>> mapList = new ArrayList<>();
            listOfSelectResult.forEach(listResult -> {
                // 如果时间相同 添加mapList
                if (listResult.getDate().equals(str)) {
                    mapList.add(listResult.getSum());
                }
            });
            listVO.setList(mapList);
            listLast.add(listVO);
        });
        return listLast;
    }

    /**
     * 获取两段时间间隔的所有月份
     *
     * @param minDate 开始时间
     * @param maxDate 结束时间
     * @return 间隔的所有月份
     * @throws ParseException parseException
     */
    private List<String> getMonthBetween(String minDate, String maxDate) throws ParseException {
        List<String> result = new ArrayList<>();
        //格式化为年月
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");

        Calendar min = Calendar.getInstance();
        Calendar max = Calendar.getInstance();

        min.setTime(sdf.parse(minDate));
        min.set(min.get(Calendar.YEAR), min.get(Calendar.MONTH), 1);

        max.setTime(sdf.parse(maxDate));
        max.set(max.get(Calendar.YEAR), max.get(Calendar.MONTH), 2);

        while (min.before(max)) {
            result.add(sdf.format(min.getTime()));
            min.add(Calendar.MONTH, 1);
        }

        return result;
    }
}
